Um guia completo para mesclar e juntar DataFrames em Python Pandas, cobrindo várias estratégias como junções interna, externa, esquerda e direita com exemplos práticos para análise global de dados.
Python Pandas Merging: Dominando Estratégias de Junção de DataFrames para Análise de Dados
A manipulação de dados é um aspecto crucial da análise de dados, e a biblioteca Pandas em Python fornece ferramentas poderosas para esse fim. Entre essas ferramentas, a mesclagem e a junção de DataFrames são operações essenciais para combinar conjuntos de dados com base em colunas ou índices comuns. Este guia abrangente explora várias estratégias de junção de DataFrames no Pandas, equipando você com o conhecimento para combinar e analisar dados de diferentes fontes de forma eficaz.
Entendendo a Mesclagem e Junção de DataFrames
Mesclar e juntar DataFrames envolve a combinação de dois ou mais DataFrames em um único DataFrame com base em uma coluna ou índice compartilhado. A principal diferença entre `merge` e `join` é que `merge` é uma função da biblioteca Pandas e geralmente junta DataFrames em colunas, enquanto `join` é um método de DataFrame que junta DataFrames principalmente em índices, embora também possa ser usado com colunas.
Conceitos Chave
- DataFrames: Estruturas de dados rotuladas bidimensionais com colunas de tipos potencialmente diferentes.
- Colunas/Índices Comuns: Colunas ou índices que compartilham o mesmo nome e tipo de dado entre os DataFrames, servindo como base para mesclagem/junção.
- Tipos de Junção: Diferentes estratégias para lidar com linhas não correspondentes durante o processo de mesclagem/junção, incluindo junções interna, externa, esquerda e direita.
Mesclagem de DataFrames com pd.merge()
A função `pd.merge()` é a ferramenta principal para mesclar DataFrames com base em colunas. Ela oferece uma maneira flexível de combinar dados com base em uma ou mais colunas comuns.
Sintaxe
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
Parâmetros
- left: O DataFrame da esquerda para mesclar.
- right: O DataFrame da direita para mesclar.
- how: O tipo de mesclagem a ser realizada ('inner', 'outer', 'left', 'right'). O padrão é 'inner'.
- on: O nome da(s) coluna(s) para juntar. Estas devem ser encontradas em ambos os DataFrames.
- left_on: O nome da(s) coluna(s) no DataFrame da esquerda a ser usada(s) como chaves de junção.
- right_on: O nome da(s) coluna(s) no DataFrame da direita a ser usada(s) como chaves de junção.
- left_index: Se True, usa o índice do DataFrame da esquerda como a(s) chave(s) de junção.
- right_index: Se True, usa o índice do DataFrame da direita como a(s) chave(s) de junção.
- sort: Classifica o DataFrame resultante lexicograficamente pelas chaves de junção. O padrão é False.
- suffixes: Uma tupla de sufixos de string a serem aplicados a nomes de colunas sobrepostos. O padrão é ('_x', '_y').
- copy: Se False, evita a cópia de dados para o novo DataFrame sempre que possível. O padrão é True.
- indicator: Se True, adiciona uma coluna chamada '_merge' indicando a origem de cada linha.
- validate: Verifica se a mesclagem é do tipo especificado. "one_to_one", "one_to_many", "many_to_one", "many_to_many".
Tipos de Junção Explicados
O parâmetro `how` em `pd.merge()` determina o tipo de junção realizada. Os diferentes tipos de junção lidam com linhas não correspondentes de maneiras diferentes.
Junção Interna (Inner Join)
Uma junção interna retorna apenas as linhas que possuem valores correspondentes em ambos os DataFrames com base nas chaves de junção. Linhas com valores não correspondentes são excluídas do resultado.
Exemplo:
Considere dois DataFrames:
import pandas as pd
# DataFrame 1: Pedidos de Clientes
df_orders = pd.DataFrame({
'order_id': [1, 2, 3, 4, 5],
'customer_id': [101, 102, 103, 104, 105],
'product_id': [1, 2, 1, 3, 2],
'quantity': [2, 1, 3, 1, 2]
})
# DataFrame 2: Informações de Clientes
df_customers = pd.DataFrame({
'customer_id': [101, 102, 103, 106],
'customer_name': ['Alice', 'Bob', 'Charlie', 'David'],
'country': ['USA', 'Canada', 'UK', 'Australia']
})
# Junção Interna
df_inner = pd.merge(df_orders, df_customers, on='customer_id', how='inner')
print(df_inner)
Saída:
order_id customer_id product_id quantity customer_name country
0 1 101 1 2 Alice USA
1 2 102 2 1 Bob Canada
2 3 103 1 3 Charlie UK
Neste exemplo, a junção interna combina os DataFrames `df_orders` e `df_customers` com base na coluna `customer_id`. Apenas os clientes que fizeram pedidos são incluídos no resultado. O cliente 'David' (customer_id 106) é excluído porque ele não tem nenhum pedido.
Junção Externa (Outer Join)
Uma junção externa retorna todas as linhas de ambos os DataFrames, incluindo linhas não correspondentes. Se uma linha não tiver uma correspondência no outro DataFrame, as colunas correspondentes conterão valores `NaN` (Not a Number).
Exemplo:
# Junção Externa
df_outer = pd.merge(df_orders, df_customers, on='customer_id', how='outer')
print(df_outer)
Saída:
order_id customer_id product_id quantity customer_name country
0 1.0 101 1.0 2.0 Alice USA
1 2.0 102 2.0 1.0 Bob Canada
2 3.0 103 1.0 3.0 Charlie UK
3 4.0 104 3.0 1.0 NaN NaN
4 5.0 105 2.0 2.0 NaN NaN
5 NaN 106 NaN NaN David Australia
A junção externa inclui todos os clientes e todos os pedidos. Os clientes 104 e 105 têm pedidos, mas sem informações de cliente, e o cliente 106 tem informações de cliente, mas sem pedidos. Os valores ausentes são representados como `NaN`.
Junção à Esquerda (Left Join)
Uma junção à esquerda retorna todas as linhas do DataFrame da esquerda e as linhas correspondentes do DataFrame da direita. Se uma linha no DataFrame da esquerda não tiver uma correspondência no DataFrame da direita, as colunas correspondentes do DataFrame da direita conterão valores `NaN`.
Exemplo:
# Junção à Esquerda
df_left = pd.merge(df_orders, df_customers, on='customer_id', how='left')
print(df_left)
Saída:
order_id customer_id product_id quantity customer_name country
0 1 101 1 2 Alice USA
1 2 102 2 1 Bob Canada
2 3 103 1 3 Charlie UK
3 4 104 3 1 NaN NaN
4 5 105 2 2 NaN NaN
A junção à esquerda inclui todos os pedidos de `df_orders`. Os clientes 104 e 105 têm pedidos, mas nenhuma informação de cliente, portanto, as colunas `customer_name` e `country` são `NaN` para esses pedidos.
Junção à Direita (Right Join)
Uma junção à direita retorna todas as linhas do DataFrame da direita e as linhas correspondentes do DataFrame da esquerda. Se uma linha no DataFrame da direita não tiver uma correspondência no DataFrame da esquerda, as colunas correspondentes do DataFrame da esquerda conterão valores `NaN`.
Exemplo:
# Junção à Direita
df_right = pd.merge(df_orders, df_customers, on='customer_id', how='right')
print(df_right)
Saída:
order_id customer_id product_id quantity customer_name country
0 1.0 101 1.0 2.0 Alice USA
1 2.0 102 2.0 1.0 Bob Canada
2 3.0 103 1.0 3.0 Charlie UK
3 NaN 106 NaN NaN David Australia
A junção à direita inclui todos os clientes de `df_customers`. O cliente 106 tem informações de cliente, mas nenhum pedido, portanto, as colunas `order_id`, `product_id` e `quantity` são `NaN` para esse cliente.
Junção de DataFrames com df.join()
O método `df.join()` é usado principalmente para juntar DataFrames com base em seus índices. Ele também pode ser usado para juntar em colunas, mas geralmente é mais conveniente usar `pd.merge()` para junções baseadas em colunas.
Sintaxe
DataFrame.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
Parâmetros
- other: O outro DataFrame para juntar.
- on: Nome da coluna para juntar. Deve ser passado se o índice não for usado como chave de junção.
- how: Como lidar com a operação dos conjuntos esquerdo e direito. O padrão é 'left'.
- lsuffix: Sufixo a ser usado do DataFrame da esquerda para substituir nomes de colunas sobrepostos.
- rsuffix: Sufixo a ser usado do DataFrame da direita para substituir nomes de colunas sobrepostos.
- sort: Classifica o DataFrame resultante lexicograficamente pelas chaves de junção. O padrão é False.
Junção por Índice
Ao juntar por índice, o parâmetro `on` não é usado.
Exemplo:
# DataFrame 1: Pedidos de Clientes com ID de Cliente como Índice
df_orders_index = df_orders.set_index('customer_id')
# DataFrame 2: Informações de Clientes com ID de Cliente como Índice
df_customers_index = df_customers.set_index('customer_id')
# Junção por Índice (Junção à Esquerda)
df_join_index = df_orders_index.join(df_customers_index, how='left')
print(df_join_index)
Saída:
order_id product_id quantity customer_name country
customer_id
101 1 1 2 Alice USA
102 2 2 1 Bob Canada
103 3 1 3 Charlie UK
104 4 3 1 NaN NaN
105 5 2 2 NaN NaN
Neste exemplo, o método `join()` é usado para realizar uma junção à esquerda no índice (`customer_id`). O resultado é semelhante à junção à esquerda usando `pd.merge()`, mas a junção é baseada no índice em vez de uma coluna.
Junção por Coluna
Para juntar em uma coluna usando `df.join()`, você precisa especificar o parâmetro `on`.
Exemplo:
# Juntando em uma coluna
df_join_column = df_orders.join(df_customers.set_index('customer_id'), on='customer_id', how='left')
print(df_join_column)
Saída:
order_id customer_id product_id quantity customer_name country
0 1 101 1 2 Alice USA
1 2 102 2 1 Bob Canada
2 3 103 1 3 Charlie UK
3 4 104 3 1 NaN NaN
4 5 105 2 2 NaN NaN
Este exemplo demonstra a junção de `df_orders` com `df_customers` usando a coluna `customer_id`. Observe que o `customer_id` é definido como o índice em `df_customers` antes de realizar a junção.
Lidando com Colunas Sobrepostas
Ao mesclar ou juntar DataFrames, é comum encontrar nomes de colunas sobrepostos (colunas com o mesmo nome em ambos os DataFrames). O Pandas fornece o parâmetro `suffixes` em `pd.merge()` e os parâmetros `lsuffix` e `rsuffix` em `df.join()` para lidar com essas situações.
Usando suffixes em pd.merge()
O parâmetro `suffixes` permite especificar sufixos que serão adicionados aos nomes de colunas sobrepostos para distingui-los.
Exemplo:
# DataFrame 1: Informações de Produtos
df_products1 = pd.DataFrame({
'product_id': [1, 2, 3],
'product_name': ['Produto A', 'Produto B', 'Produto C'],
'price': [10, 20, 15]
})
# DataFrame 2: Informações de Produtos (com preços potencialmente atualizados)
df_products2 = pd.DataFrame({
'product_id': [1, 2, 4],
'product_name': ['Produto A', 'Produto B', 'Produto D'],
'price': [12, 18, 25]
})
# Mesclar com sufixos
df_merged_suffixes = pd.merge(df_products1, df_products2, on='product_id', suffixes=('_antigo', '_novo'))
print(df_merged_suffixes)
Saída:
product_id product_name_antigo price_antigo product_name_novo price_novo
0 1 Produto A 10 Produto A 12
1 2 Produto B 20 Produto B 18
Neste exemplo, as colunas `product_name` e `price` estão presentes em ambos os DataFrames. O parâmetro `suffixes` adiciona os sufixos `_antigo` e `_novo` para distinguir as colunas dos DataFrames da esquerda e da direita, respectivamente.
Usando lsuffix e rsuffix em df.join()
Os parâmetros `lsuffix` e `rsuffix` fornecem funcionalidade semelhante para `df.join()`. `lsuffix` anexa ao DataFrame da esquerda com colunas sobrepostas, e `rsuffix` ao DataFrame da direita.
Exemplo:
# Junção com lsuffix e rsuffix
df_products1_index = df_products1.set_index('product_id')
df_products2_index = df_products2.set_index('product_id')
df_joined_suffixes = df_products1_index.join(df_products2_index, lsuffix='_antigo', rsuffix='_novo', how='outer')
print(df_joined_suffixes)
Saída:
product_name_antigo price_antigo product_name_novo price_novo
product_id
1 Produto A 10.0 Produto A 12.0
2 Produto B 20.0 Produto B 18.0
3 Produto C 15.0 NaN NaN
4 NaN NaN Produto D 25.0
Exemplos Práticos e Casos de Uso
A mesclagem e a junção de DataFrames são amplamente utilizadas em vários cenários de análise de dados. Aqui estão alguns exemplos práticos:
Combinando Dados de Vendas com Informações de Produtos
Um caso de uso comum é combinar dados de vendas com informações de produtos. Suponha que você tenha um DataFrame contendo transações de vendas e outro DataFrame contendo detalhes do produto. Você pode mesclar esses DataFrames para enriquecer os dados de vendas com informações do produto.
Exemplo:
# Dados de Transações de Vendas
df_sales = pd.DataFrame({
'transaction_id': [1, 2, 3, 4, 5],
'product_id': [101, 102, 103, 101, 104],
'quantity': [2, 1, 3, 1, 2],
'sales_date': ['2023-01-15', '2023-02-20', '2023-03-10', '2023-04-05', '2023-05-01']
})
# Dados de Informações de Produtos
df_products = pd.DataFrame({
'product_id': [101, 102, 103, 104],
'product_name': ['Laptop', 'Mouse', 'Teclado', 'Monitor'],
'category': ['Eletrônicos', 'Eletrônicos', 'Eletrônicos', 'Eletrônicos'],
'price': [1200, 25, 75, 300]
})
# Mesclar Dados de Vendas com Informações de Produtos
df_sales_enriched = pd.merge(df_sales, df_products, on='product_id', how='left')
print(df_sales_enriched)
Saída:
transaction_id product_id quantity sales_date product_name category price
0 1 101 2 2023-01-15 Laptop Eletrônicos 1200
1 2 102 1 2023-02-20 Mouse Eletrônicos 25
2 3 103 3 2023-03-10 Teclado Eletrônicos 75
3 4 101 1 2023-04-05 Laptop Eletrônicos 1200
4 5 104 2 2023-05-01 Monitor Eletrônicos 300
O DataFrame resultante `df_sales_enriched` contém as transações de vendas juntamente com as informações correspondentes do produto, permitindo uma análise mais detalhada das tendências de vendas e do desempenho do produto.
Combinando Dados de Clientes com Informações Demográficas
Outro caso de uso comum é combinar dados de clientes com informações demográficas. Isso permite analisar o comportamento do cliente com base em fatores demográficos.
Exemplo:
# Dados de Clientes
df_customers = pd.DataFrame({
'customer_id': [1, 2, 3, 4, 5],
'customer_name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'city': ['Nova York', 'Londres', 'Tóquio', 'Sydney', 'Berlim']
})
# Dados de Informações Demográficas
df_demographics = pd.DataFrame({
'city': ['Nova York', 'Londres', 'Tóquio', 'Sydney', 'Berlim'],
'population': [8419000, 8982000, 13960000, 5312000, 3769000],
'average_income': [75000, 65000, 85000, 90000, 55000]
})
# Mesclar Dados de Clientes com Informações Demográficas
df_customer_demographics = pd.merge(df_customers, df_demographics, on='city', how='left')
print(df_customer_demographics)
Saída:
customer_id customer_name city population average_income
0 1 Alice Nova York 8419000 75000
1 2 Bob Londres 8982000 65000
2 3 Charlie Tóquio 13960000 85000
3 4 David Sydney 5312000 90000
4 5 Eve Berlim 3769000 55000
O DataFrame resultante `df_customer_demographics` contém dados de clientes juntamente com informações demográficas de suas respectivas cidades, permitindo a análise do comportamento do cliente com base nas demografias da cidade.
Analisando Dados Globais da Cadeia de Suprimentos
A mesclagem do Pandas é valiosa para analisar dados globais da cadeia de suprimentos, onde as informações são frequentemente distribuídas por várias tabelas. Por exemplo, vincular dados de fornecedores, informações de envio e números de vendas pode revelar gargalos e otimizar a logística.
Exemplo:
# Dados de Fornecedores
df_suppliers = pd.DataFrame({
'supplier_id': [1, 2, 3],
'supplier_name': ['GlobalTech', 'EuroParts', 'AsiaSource'],
'location': ['Taiwan', 'Germany', 'China']
})
# Dados de Envio
df_shipments = pd.DataFrame({
'shipment_id': [101, 102, 103, 104],
'supplier_id': [1, 2, 3, 1],
'destination': ['EUA', 'Canadá', 'Austrália', 'Japão'],
'shipment_date': ['2023-01-10', '2023-02-15', '2023-03-20', '2023-04-25']
})
# Mesclar Dados de Fornecedores e Envio
df_supply_chain = pd.merge(df_shipments, df_suppliers, on='supplier_id', how='left')
print(df_supply_chain)
Saída:
shipment_id supplier_id destination shipment_date supplier_name location
0 101 1 EUA 2023-01-10 GlobalTech Taiwan
1 102 2 Canadá 2023-02-15 EuroParts Germany
2 103 3 Austrália 2023-03-20 AsiaSource China
3 104 1 Japão 2023-04-25 GlobalTech Taiwan
Técnicas Avançadas de Mesclagem
Mesclagem em Múltiplas Colunas
Você pode mesclar DataFrames com base em várias colunas, passando uma lista de nomes de colunas para o parâmetro `on`.
Exemplo:
# DataFrame 1
df1 = pd.DataFrame({
'product_id': [1, 1, 2, 2],
'color': ['red', 'blue', 'red', 'blue'],
'quantity': [10, 15, 20, 25]
})
# DataFrame 2
df2 = pd.DataFrame({
'product_id': [1, 1, 2, 2],
'color': ['red', 'blue', 'red', 'blue'],
'price': [5, 7, 8, 10]
})
# Mesclar em múltiplas colunas
df_merged_multiple = pd.merge(df1, df2, on=['product_id', 'color'], how='inner')
print(df_merged_multiple)
Saída:
product_id color quantity price
0 1 red 10 5
1 1 blue 15 7
2 2 red 20 8
3 2 blue 25 10
Mesclagem com Nomes de Colunas Diferentes
Se as colunas de junção tiverem nomes diferentes nos dois DataFrames, você pode usar os parâmetros `left_on` e `right_on` para especificar os nomes das colunas a serem usadas para a mesclagem.
Exemplo:
# DataFrame 1
df1 = pd.DataFrame({
'product_id': [1, 2, 3],
'product_name': ['Produto A', 'Produto B', 'Produto C']
})
# DataFrame 2
df2 = pd.DataFrame({
'id': [1, 2, 4],
'price': [10, 20, 25]
})
# Mesclar com nomes de colunas diferentes
df_merged_different = pd.merge(df1, df2, left_on='product_id', right_on='id', how='left')
print(df_merged_different)
Saída:
product_id product_name id price
0 1 Produto A 1.0 10.0
1 2 Produto B 2.0 20.0
2 3 Produto C NaN NaN
Usando indicator para Análise de Mesclagem
O parâmetro `indicator` em `pd.merge()` adiciona uma coluna chamada `_merge` ao DataFrame resultante, indicando a origem de cada linha. Isso é útil para entender quais linhas foram correspondidas e quais não foram.
Exemplo:
# Mesclar com indicador
df_merged_indicator = pd.merge(df_orders, df_customers, on='customer_id', how='outer', indicator=True)
print(df_merged_indicator)
Saída:
order_id customer_id product_id quantity customer_name country _merge
0 1.0 101 1.0 2.0 Alice USA both
1 2.0 102 2.0 1.0 Bob Canada both
2 3.0 103 1.0 3.0 Charlie UK both
3 4.0 104 3.0 1.0 NaN NaN left_only
4 5.0 105 2.0 2.0 NaN NaN left_only
5 NaN 106 NaN NaN David Australia right_only
A coluna `_merge` indica se a linha é de ambos os DataFrames (`both`), apenas do DataFrame da esquerda (`left_only`) ou apenas do DataFrame da direita (`right_only`).
Validando Tipos de Mesclagem
O parâmetro `validate` garante que a operação de mesclagem esteja alinhada com os tipos de relacionamento esperados entre os DataFrames (por exemplo, 'one_to_one', 'one_to_many'). Isso ajuda a prevenir inconsistências e erros nos dados.
Exemplo:
# Exemplo com validação um para um
df_users = pd.DataFrame({
'user_id': [1, 2, 3],
'username': ['john_doe', 'jane_smith', 'peter_jones']
})
df_profiles = pd.DataFrame({
'user_id': [1, 2, 3],
'profile_description': ['Software Engineer', 'Data Scientist', 'Project Manager']
})
# Realizando uma mesclagem um para um com validação
merged_df = pd.merge(df_users, df_profiles, on='user_id', validate='one_to_one')
print(merged_df)
Se a mesclagem violar a validação especificada (por exemplo, um relacionamento muitos para um quando 'one_to_one' é especificado), um `MergeError` será gerado, alertando sobre possíveis problemas de integridade de dados.
Considerações de Desempenho
A mesclagem e a junção de DataFrames podem ser computacionalmente caras, especialmente para grandes conjuntos de dados. Aqui estão algumas dicas para melhorar o desempenho:
- Use o tipo de junção apropriado: Escolher o tipo de junção correto pode impactar significativamente o desempenho. Por exemplo, se você precisar apenas de linhas correspondentes, use uma junção interna.
- Indexe as colunas de junção: Indexar as colunas de junção pode acelerar o processo de mesclagem.
- Use tipos de dados apropriados: Certifique-se de que as colunas de junção tenham tipos de dados compatíveis.
- Evite cópias desnecessárias: Defina `copy=False` em `pd.merge()` e `df.join()` para evitar a criação de cópias desnecessárias dos dados.
Conclusão
A mesclagem e a junção de DataFrames são operações fundamentais na análise de dados. Ao entender os diferentes tipos de junção e técnicas, você pode combinar e analisar dados de várias fontes de forma eficaz, desbloqueando insights valiosos e impulsionando a tomada de decisões informadas. Desde a combinação de dados de vendas com informações de produtos até a análise de cadeias de suprimentos globais, dominar essas técnicas o capacitará a lidar com tarefas complexas de manipulação de dados com confiança. Lembre-se de considerar as implicações de desempenho ao trabalhar com grandes conjuntos de dados e alavanque recursos avançados como os parâmetros `indicator` e `validate` para análises mais robustas e perspicazes.